/* Copyright (c) 2023 Renmin University of China
RMDB is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
        http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

#include "analyze.h"

/**
 * @description: 分析器，进行语义分析和查询重写，需要检查不符合语义规定的部分
 * @param {shared_ptr<ast::TreeNode>} parse parser生成的结果集
 * @return {shared_ptr<Query>} /home/sqb/桌面/DBS_share/rmdb/src/optimizer/planner.cpp
 Query
 */
std::shared_ptr<Query> Analyze::do_analyze(std::shared_ptr<ast::TreeNode> parse)
{
    std::shared_ptr<Query> query = std::make_shared<Query>();
    if (auto x = std::dynamic_pointer_cast<ast::SelectStmt>(parse))
    {
        // 处理表名
        query->tables = std::move(x->tabs);
        /** TODO: 检查表是否存在 */
        //down!
        for (auto& tab : query->tables)
        {
            if (!sm_manager_->db_.is_table(tab))
                throw TableNotFoundError(tab);
        }

        // 处理target list，再target list中添加上表名，例如 a.id
        for (auto& sv_sel_col : x->cols) {
            TabCol sel_col = { .tab_name = sv_sel_col->tab_name, .col_name = sv_sel_col->col_name };
            query->cols.push_back(sel_col);
        }

        std::vector<ColMeta> all_cols;
        get_all_cols(query->tables, all_cols);
        if (query->cols.empty()) {
            // select all columns
            for (auto& col : all_cols) {
                TabCol sel_col = { .tab_name = col.tab_name, .col_name = col.name };
                query->cols.push_back(sel_col);
            }
        }
        else {
            // infer table name from column name
            for (auto& sel_col : query->cols) {
                sel_col = check_column(all_cols, sel_col);  // 列元数据校验
            }
        }
        //处理where条件
        get_clause(x->conds, query->conds);
        check_clause(query->tables, query->conds);

        //数量限制
        query->limit = x->limit;

    }
    else if (auto x = std::dynamic_pointer_cast<ast::UpdateStmt>(parse)) {
        /** TODO: */
        //down!

        //不检查列试试 
        // std::vector<ColMeta> all_cols;
        // get_all_cols(x->tab_name, all_cols);
        // TabMeta & tTabMeta=sm_manager_->db_.get_table(x->tab_name);

        //初始化并添加每个条件语句
        for (auto& a_set_clause : x->set_clauses)
        {
            SetClause stl;
            stl.lhs = { .tab_name = x->tab_name,.col_name = a_set_clause->col_name };
            //检查是否存在左值列 检查了要报错
            // stl.lhs=check_column(all_cols,stl.lhs);

            // //在这里做左右的类型转换
            // ColMeta lcol=*(tTabMeta.get_col(a_set_clause->col_name));
            // Value rval=convert_sv_value(a_set_clause->val);
            stl.rhs = convert_sv_value(a_set_clause->val);
            //确定set语句右值是否为表达式
            stl.is_expr = a_set_clause->is_expr;
            query->set_clauses.push_back(stl);
        }
        //处理where条件
        get_clause(x->conds, query->conds);
        check_clause({ x->tab_name }, query->conds);
    }
    else if (auto x = std::dynamic_pointer_cast<ast::DeleteStmt>(parse)) {
        //处理where条件
        get_clause(x->conds, query->conds);
        check_clause({ x->tab_name }, query->conds);
    }
    else if (auto x = std::dynamic_pointer_cast<ast::InsertStmt>(parse)) {
        // 处理insert 的values值
        for (auto& sv_val : x->vals) {
            query->values.push_back(convert_sv_value(sv_val));
        }
    }
    else {
        // do nothing
    }
    query->parse = std::move(parse);
    return query;
}

//mine:检查目标列的所有列中是否存在target列
TabCol Analyze::check_column(const std::vector<ColMeta>& all_cols, TabCol target) {
    if (target.tab_name.empty()) {
        // Table name not specified, infer table name from column name
        std::string tab_name;
        for (auto& col : all_cols) {
            if (col.name == target.col_name) {
                if (!tab_name.empty()) {
                    throw AmbiguousColumnError(target.col_name);
                }
                tab_name = col.tab_name;
            }
        }
        if (tab_name.empty()) {
            throw ColumnNotFoundError(target.col_name);
        }
        target.tab_name = tab_name;
    }
    else {
        /** TODO: Make sure target column exists */
        //down!
        if (!(sm_manager_->db_.is_table(target.tab_name)))
            throw ColumnNotFoundError(target.col_name);

        TabMeta& tTabMeta = sm_manager_->db_.get_table(target.tab_name);
        if (!tTabMeta.is_col(target.col_name))
            throw ColumnNotFoundError(target.col_name);

    }
    return target;
}

//mine:得到所有表的列
void Analyze::get_all_cols(const std::vector<std::string>& tab_names, std::vector<ColMeta>& all_cols) {
    for (auto& sel_tab_name : tab_names) {
        // 这里db_不能写成get_db(), 注意要传指针
        const auto& sel_tab_cols = sm_manager_->db_.get_table(sel_tab_name).cols;
        all_cols.insert(all_cols.end(), sel_tab_cols.begin(), sel_tab_cols.end());
    }
}

//mine:完善查询语句中的条件限定
void Analyze::get_clause(const std::vector<std::shared_ptr<ast::BinaryExpr>>& sv_conds, std::vector<Condition>& conds) {
    conds.clear();
    for (auto& expr : sv_conds) {
        Condition cond;
        cond.lhs_col = { .tab_name = expr->lhs->tab_name, .col_name = expr->lhs->col_name };
        cond.op = convert_sv_comp_op(expr->op);
        if (auto rhs_val = std::dynamic_pointer_cast<ast::Value>(expr->rhs)) {
            cond.is_rhs_val = true;
            cond.rhs_val = convert_sv_value(rhs_val);
        }
        else if (auto rhs_col = std::dynamic_pointer_cast<ast::Col>(expr->rhs)) {
            cond.is_rhs_val = false;
            cond.rhs_col = { .tab_name = rhs_col->tab_name, .col_name = rhs_col->col_name };
        }
        conds.push_back(cond);
    }
}

void Analyze::check_clause(const std::vector<std::string>& tab_names, std::vector<Condition>& conds) {
    // auto all_cols = get_all_cols(tab_names);
    std::vector<ColMeta> all_cols;
    get_all_cols(tab_names, all_cols);
    // Get raw values in where clause
    for (auto& cond : conds) {
        // Infer table name from column name
        cond.lhs_col = check_column(all_cols, cond.lhs_col);
        if (!cond.is_rhs_val) {
            cond.rhs_col = check_column(all_cols, cond.rhs_col);
        }
        TabMeta& lhs_tab = sm_manager_->db_.get_table(cond.lhs_col.tab_name);
        auto lhs_col = lhs_tab.get_col(cond.lhs_col.col_name);
        ColType lhs_type = lhs_col->type;
        ColType rhs_type;
        if (cond.is_rhs_val) {
            cond.rhs_val.init_raw(lhs_col->len);
            rhs_type = cond.rhs_val.type;
        }
        else {
            TabMeta& rhs_tab = sm_manager_->db_.get_table(cond.rhs_col.tab_name);
            auto rhs_col = rhs_tab.get_col(cond.rhs_col.col_name);
            rhs_type = rhs_col->type;
        }
        //如果左右列类型不等，适当类型转换 用于where语句
        if (lhs_type != rhs_type) {
            //添加大数 日期等类型的兼容
            if (lhs_type == TYPE_BIGINT && rhs_type == TYPE_INT) {
                cond.rhs_val.type = TYPE_BIGINT;
                *(long long*)(cond.rhs_val.raw->data) = (long long)cond.rhs_val.int_val;
            }
            else if (lhs_type == TYPE_FLOAT && rhs_type == TYPE_INT) {
                cond.rhs_val.type = TYPE_FLOAT;
                *(float*)(cond.rhs_val.raw->data) = (float)cond.rhs_val.int_val;
            }
            else if (lhs_type == TYPE_STRING && rhs_type == TYPE_TIME) {
                cond.rhs_val.type = TYPE_STRING;
                cond.rhs_val.str_val = cond.rhs_val.time_val;
            }
            else
                throw IncompatibleTypeError(coltype2str(lhs_type), coltype2str(rhs_type));
        }
    }
}

//mine:将抽象树的目标列或值转换为查询树的列或值
Value Analyze::convert_sv_value(const std::shared_ptr<ast::Value>& sv_val) {
    Value val;
    //添加大数 日期从抽象树的转换
    if (auto int_lit = std::dynamic_pointer_cast<ast::IntLit>(sv_val)) {
        val.set_int(int_lit->val);
    }
    else if (auto bigInt_lit = std::dynamic_pointer_cast<ast::BigIntLit>(sv_val)) {
        val.set_bigInt(bigInt_lit->val);
    }
    else if (auto float_lit = std::dynamic_pointer_cast<ast::FloatLit>(sv_val)) {
        val.set_float(float_lit->val);
    }
    else if (auto str_lit = std::dynamic_pointer_cast<ast::StringLit>(sv_val)) {
        val.set_str(str_lit->val);
    }
    else if (auto time_lit = std::dynamic_pointer_cast<ast::TimeLit>(sv_val)) {
        val.set_time(time_lit->val);
    }
    else {
        throw InternalError("Unexpected sv value type");
    }
    return val;
}

//mine:将抽象树的运行符转换为查询树的运算符
CompOp Analyze::convert_sv_comp_op(ast::SvCompOp op) {
    std::map<ast::SvCompOp, CompOp> m = {
        {ast::SV_OP_EQ, OP_EQ}, {ast::SV_OP_NE, OP_NE}, {ast::SV_OP_LT, OP_LT},
        {ast::SV_OP_GT, OP_GT}, {ast::SV_OP_LE, OP_LE}, {ast::SV_OP_GE, OP_GE},
    };
    return m.at(op);
}
